<!-- 通用上传图片组件 -->
<template>
  <div class="photo-upload-wrap">
    <px-upload
      v-model:file-list="photoList"
      class="photo-upload"
      :class="props.photoType === 'view' || photoList?.length >= countLimit ? 'hidden-trigger' : ''"
      list-type="picture-card"
      :limit="props.countLimit"
      accept=".jpg,.png,.jpeg,.gif,.bmp"
      :action="actionUrl"
      :headers="headers"
      :data="props.photoData"
      :before-upload="beforeUpload"
      :on-progress="upLoadProgress"
      :on-success="uploadSuccess"
      :on-error="uploadError"
      :on-exceed="uploadExceed"
    >
      <template #trigger>
        <div class="px-upload__trigger">
          <px-icon><Plus /></px-icon>
          <!-- <span>图片上传</span> -->
        </div>
      </template>
      <template #file="{ file }">
        <div>
          <img class="px-upload-list__item-thumbnail" :src="file.url || file.fileUrl" alt="" />
          <span class="px-upload-list__item-actions">
            <span @click="photoPreview(file)">
              <px-icon><zoom-in /></px-icon>
            </span>
            <span v-if="props.photoType === 'view'" @click="photoDownload(file)">
              <px-icon><Download /></px-icon>
            </span>
            <span v-if="props.photoType === 'add' || props.photoType === 'edit'" @click="photoDelete(file)">
              <px-icon><Delete /></px-icon>
            </span>
          </span>
        </div>
      </template>
      <!-- <template v-if="props.photoType === 'add' || props.photoType === 'edit'" #tip>
        <div class="px-upload__tip">
          ⽀持jpg/png/jpeg/gif/bmp图片格式，且图片⼤⼩不超过20M<span v-if="props.countLimit !== 999">，且图片数量不超过{{ props.countLimit }}个</span>
        </div>
      </template> -->
    </px-upload>
    <px-image-viewer
      v-if="photoShow"
      style="z-index: 999999"
      hide-on-click-modal
      :draggable="false"
      :url-list="viewerPhotoList"
      @close="closePhotoPreview"
    />
  </div>
</template>
<script setup lang="ts">
import { deleteFile, deleteFileDms } from "@/api/common";
import { getToken } from "@/utils/auth";
import { PxImageViewer, PxMessage } from "px-ui";
import { getCurrentInstance, reactive, toRefs, watch } from "vue";
// 调用父级-改变图片列表方法，查看时不调用
const emits = defineEmits(["changePhotoList", "savePhotoStatus"]);
// 父级传过来的值
const props = defineProps({
  // 图片上传类型add：新增，edit：编辑，view：查看
  photoType: {
    type: String,
    default: "add",
    required: true
  },
  // 文档上传接口url
  actionUrl: {
    type: String,
    default: "/ifp/sharing/api/v1/file/upload",
    required: false
  },
  downloadUrl: {
    type: String,
    default: "/sharing/api/v1/file/download",
    required: false
  },
  // 图片上传接口数据
  photoData: {
    type: Object,
    default: () => {
      return {};
    },
    required: true
  },
  row: {
    type: Object,
    default: () => {
      return {};
    },
    required: true
  },
  // 文件上传个数
  countLimit: {
    type: Number,
    default: 999,
    required: false
  },
  // 图片上传类型为edit/view时，已上传的图片列表
  photoList2: {
    type: Array,
    default: () => {
      return [];
    },
    required: true
  },
  // 是否自定义上传文件
  isCustomUpload: {
    type: Boolean,
    required: false,
    default: false
  }
});

// 页面本身的值
const { proxy }: any = getCurrentInstance();
const state = reactive<any>({
  headers: {
    Authorization: "Bearer " + getToken().accessToken || "",
    facCode: localStorage.getItem("facCode") || ""
  },
  photoList: [], // 图片列表
  photoShow: false, // 图片预览显示
  viewerPhotoList: [], // 预览图片列表
  photoNumber: 0 // 图片上传数量
});
const { headers, photoList, photoShow, viewerPhotoList, photoNumber } = toRefs(state);
// 监视图片上传类型
watch(
  () => [props.photoType, props.photoList2, props.row],
  val => {
    console.log(props.row);
    photoList.value = val[1] || [];
  },
  { immediate: true }
);

// 上传图片之前判断大小及格式
const beforeUpload = rawFile => {
  const acceptList = ["jpg", "png", "jpeg", "gif", "bmp"];
  let fileType = rawFile.name.split(".").pop().toLowerCase();
  if (acceptList.indexOf(fileType) === -1) {
    PxMessage.error("只能上传 jpg/png/jpeg/gif/bmp 格式的图片");
    return false;
  } else if (rawFile.size / 1024 / 1024 > 20) {
    PxMessage.error("上传图片大小不能超过20M");
    return false;
  }
  return true;
};
// 上传过程中值，页面不能保存
const upLoadProgress = () => {
  emits("savePhotoStatus", true);
};
// 上传成功状态
const uploadSuccess = (response, uploadFile, uploadFiles) => {
  photoNumber.value++;
  // 上传成功通知页面可以保存
  if (photoNumber.value === uploadFiles.length) {
    emits("savePhotoStatus", false);
  }
  if (response.success) {
    loadImage({
      url: response?.data?.fileUrl,
      callBack: () => {
        emits("changePhotoList", photoList.value, props.row);
        emits("savePhotoStatus", false);
      }
    });
  } else {
    // 后台返回上传失败信息
    photoList.value.shift();
    PxMessage.error(response.msg);
    console.log(props.row);
    emits("changePhotoList", photoList.value, props.row);
    photoNumber.value--;
  }
};
// 上传失败状态
const uploadError = error => {
  // 此处由于后端未处理，前端先统一写"图片上传失败，请重试"
  photoList.value.shift();
  PxMessage.error("图片上传失败，请重试");
  emits("changePhotoList", photoList.value, props.row);
  photoNumber.value--;
};
// 上传个数超出限制
const uploadExceed = files => {
  PxMessage.error(`上传图片数量不能超过${props.countLimit}个`);
};
// 图片预览
const photoPreview = file => {
  photoShow.value = true;
  const index = photoList.value.indexOf(file);
  let viewerList = [...photoList.value];
  let tempList = [];
  for (let i = 0; i < index; i++) {
    tempList.push(viewerList.shift());
  }
  viewerPhotoList.value = viewerList.concat(tempList).map(file => file.url || file.fileUrl);
};
// 关闭图片预览
const closePhotoPreview = () => {
  photoShow.value = false;
};
// 下载图片
const photoDownload = file => {
  const params = {
    id: file?.response?.data?.id ? file?.response?.data?.id : file.id,
    fileName: file?.response?.data?.fileName ? file?.response?.data?.fileName : file.fileName,
    moduleName: props.photoData?.moduleName
  };
  proxy.download("post", props.downloadUrl, params, file.fileName);
};
// 删除图片
const photoDelete = async file => {
  const id = file?.response?.data?.id ? file?.response?.data?.id : file.id;
  const params = {
    fileId: [id]
  };
  props.isCustomUpload ? await deleteFileDms({ id }) : await deleteFile(params);
  PxMessage.success("图片删除成功");
  photoList.value = photoList.value.filter(item => item !== file);
  emits("changePhotoList", photoList.value, props.row);
  photoNumber.value--;
};
// 图片加载时出错兼容
const loadImage = ({ url, maxAttempts = 10, currentAttempt = 1, callBack }) => {
  const img = new Image();

  img.onload = function () {
    // 成功加载时设置图片地址
    callBack();
  };

  img.onerror = function () {
    if (currentAttempt < maxAttempts) {
      console.log(`第 ${currentAttempt} 次尝试失败，正在重试...`);
      // 200ms后重试（可选延迟）
      setTimeout(() => {
        loadImage({ url, maxAttempts, currentAttempt: currentAttempt + 1, callBack });
      }, 200);
    } else {
      console.error(`图片加载失败，已尝试 ${maxAttempts} 次`);
    }
  };
  img.src = url;
};
</script>

<style lang="scss" scoped>
.photo-upload-wrap {
  float: left;
  min-height: 50px;

  .photo-upload {
    :deep(.px-upload-list--picture-card) {
      --px-upload-list-picture-card-size: 30px;

      position: relative;
      min-height: 30px;

      .px-upload--picture-card i {
        font-size: 16px !important;
      }

      .px-upload--picture-card {
        --px-upload-picture-card-size: 50px;

        position: absolute;
        top: 0;
        left: 0;
        display: block;
        height: 50px;
        text-align: center;
      }

      .px-upload-list__item:first-of-type {
        margin-left: 60px;
      }

      .px-upload-list__item {
        width: 50px !important;
        height: 50px !important;

        .px-icon {
          font-size: 16px;
        }
      }

      .px-upload-list__item-actions span + span {
        margin-left: 5px;
      }

      .px-upload__trigger {
        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
        height: 100%;
        color: #666;

        span {
          font-size: 14px;
          color: rgb(0 0 0 / 45%);
        }
      }

      .px-upload__tip {
        font-size: 12px;
        color: rgb(0 0 0 / 60%);
      }
    }

    &.hidden-trigger {
      :deep(.px-upload-list--picture-card) {
        min-height: 0;

        .px-upload--picture-card {
          display: none;
        }

        .px-upload-list__item:first-of-type {
          margin-left: 0;
        }
      }
    }
  }

  :deep(.px-image-viewer__wrapper) {
    .px-image-viewer__prev {
      top: calc(100vh - 94px);
      left: calc(50% + 98px);
      transform: translateY(0);
    }

    .px-image-viewer__next {
      top: calc(100vh - 94px);
      left: calc(50% + 150px);
      transform: translateY(0);
    }

    .px-image-viewer__actions {
      bottom: 50px;
      left: calc(50% - 52px);
    }

    .px-image-viewer__close {
      top: 150px;
    }
  }
}
</style>
